package com.ruoyi.common.core.annotation;

import com.alibaba.fastjson.JSON;
import com.ruoyi.common.core.exception.CustomException;

import javax.validation.Constraint;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import javax.validation.Validation;
import java.lang.annotation.Documented;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

@Documented
@Constraint(validatedBy = {ValidJson.ValidJsonValidator.class })
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
@Repeatable(ValidJson.List.class)
public @interface ValidJson {
    String message() default "Invalid json";
    Class<?> jsonClass() default Object.class;
    Class<?>[] groups() default { };
    Class<?>[] payload() default { };

    @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
    @Retention(RUNTIME)
    @Documented
    @interface List {
        ValidJson[] value();
    }

    class ValidJsonValidator implements ConstraintValidator<ValidJson, String> {
        private Class<?> jsonClass;

        @Override
        public void initialize(ValidJson constraintAnnotation) {
            jsonClass = constraintAnnotation.jsonClass();
        }

        @Override
        public boolean isValid(String value, ConstraintValidatorContext context) {
            try {
                if (jsonClass == Object.class) {
                    return true;
                }
                Object obj = JSON.parseObject(value, jsonClass);
                Validation.buildDefaultValidatorFactory()
                        .getValidator()
                        .validate(obj)
                        .stream()
                        .findAny()
                        .ifPresent(e -> {throw new CustomException(e.getMessage());});
                return true;
            } catch (Exception e) {
                return false;
            }
        }
    }
}
